AddCSLuaFile( "cl_init.lua" )
AddCSLuaFile( "shared.lua" )
include('shared.lua')     
ENT.Base = "base_wire_entity"

function ENT:Initialize()
	self.LoadSound = "weapons/crossbow/bolt_load1.wav" 
	self.ShootSound = "weapons/mortar/mortar_explode2.wav"
	self.FuseSound = "weapons/flaregun/burn.wav"
	
	self:DrawShadow( true )
	self:SetModel( "models/solidarity/cannon.mdl" )
	self:PhysicsInit( SOLID_VPHYSICS )
	self:SetMoveType( MOVETYPE_VPHYSICS )
	self:SetSolid( SOLID_VPHYSICS )
	self:GetPhysicsObject():SetMass( 500 ) --it's pretty heavy
	local phys = self:GetPhysicsObject()  	
	if (phys:IsValid()) then  		
		phys:Wake()
		phys:EnableMotion(true)
	end
	
	self.Inputs = Wire_CreateInputs( self.Entity, { "Fire" } ) --add our wire input
	self.Outputs = Wire_CreateOutputs( self.Entity, { "Stage"} ) --0: Unloaded, 1: Loading, 2: Loaded, 3: Firing

	self:SetNetworkedBool( "loaded", false ) --we're not loaded
	self:SetNetworkedBool( "loading", false ) --nor are we loading
	self:SetNetworkedBool( "firing", false ) --and we're definitely not firing
	self.WireDebugName = "Cannon"
	
	if self.fusemin == nil then
		self:SetDefaultValues()
	end
end

function ENT:TriggerInput(iname, value)
	if (iname == "Fire") then
		if value == 1 then
			if self:GetNetworkedBool( "loaded" ) then
				self:StartFuse( 2, 4 )
			end
		end
	end
end

function ENT:SpawnFunction( ply, tr ) --when spawned from the entities tab
	if not tr.Hit then return end
	
	local ent = ents.Create( self.Classname )
	ent:SetPos( tr.HitPos + tr.HitNormal * 8 )
	ent:Spawn()
	ent:Activate()
	
	return ent
end

function ENT:PhysicsCollide(tblData)
	local hitent = tblData.HitEntity
	if hitent:GetClass() == "sd_cannonball" then --if we hit a cannonball...
		if not self:GetNetworkedBool( "loaded" ) && not self:GetNetworkedBool( "loading" ) && not self:GetNetworkedBool( "firing" ) && not hitent:GetNetworkedBool( "fired" ) then --if we're not already loaded/loading or firing or catching an already-fired ball...
			if tblData.HitPos:Distance( self.Entity:GetPos() ) < 5 then --if it's near the end of the cannon (the origin is at the tip)
				self:StartLoad( 3, 5, hitent ) --load it up
			end
		end
	end
end

function ENT:Use( act, caller )	
	if self.Entity:GetNetworkedBool( "loaded" ) then --are we 100% loaded?
		self:StartFuse( self.fusemin, self.fusemax ) --let 'er rip
	end
end

function ENT:SetDefaultValues()
	self.distmul = 2 --give it the default settings
	self.spreadmul = 1
	self.fusemin = 2
	self.fusemax = 4
	self.loadmin = 3
	self.loadmax = 5
	self.shouldexplode = 1
	self.shouldignite = 1
	self.shoulddestroy = 1
	self.playsound = 1
end

function ENT:StartFuse( mintime, maxtime ) --it's the final countdown! (doo doo dooo doo)
	self.Entity:SetNetworkedBool( "loaded", false ) --we're no longer idle on 'loaded'...
	self.Entity:SetNetworkedBool( "firing", true ) --we're firing!
	Wire_TriggerOutput(self.Entity, "Stage", 3)
	self:EmitFuseSounds( true ) --start our fuse sound
	timer.Simple( math.random(mintime, maxtime), function()
		self:EmitFuseSounds( false ) --countdown is done, stop our fuse sound
		self:EmitShootEffects() --give a nice explosion and smoke effect
		self:EmitShootSounds( true, 150 ) --"boom!"
		self:Shoot() --actually shoot the cannonball
		self:KickBack( -99000 ) --kick back the cannon itself
		self.Entity:SetNetworkedBool( "firing", false ) --we've fired away
		Wire_TriggerOutput(self.Entity, "Stage", 0)
	end )
end

function ENT:StartLoad( mintime, maxtime, cannonball ) --load it up!
	self.Entity:SetNetworkedBool("loading", true ) --we're going, cap'n!
	Wire_TriggerOutput(self.Entity, "Stage", 1)
	cannonball:Remove() --get rid of the original cannonball (put it in the cannon)
	self:EmitLoadSounds( true, 100 ) --play our sound
	timer.Simple( math.random( mintime, maxtime ), function() --it takes a while
		self.Entity:SetNetworkedBool( "loading", false ) --we're done loading!
		self.Entity:SetNetworkedBool( "loaded", true ) ----^
		Wire_TriggerOutput(self.Entity, "Stage", 2)
	end )
end

function ENT:EmitFuseSounds( playtoggle, mul ) --bool play, int mul(tiplier)  (mul is optional)
	if self.playsound == 1 then
		if not mul then mul = 100 end
		if playtoggle then
			self.Fuseloop = CreateSound( self, self.FuseSound )
			self.Fuseloop:Play()
		else
			self.Fuseloop:Stop()
		end
	end
end

function ENT:EmitShootSounds( playtoggle, mul ) --bool play, int mul(tiplier)  (mul is optional)
	if self.playsound == 1 then
		if not mul then mul = 100 end
		if playtoggle then
			util.PrecacheSound( self.ShootSound )
			self.Entity:EmitSound( self.ShootSound, mul, 100 )
		end
	end
end

function ENT:EmitLoadSounds( playtoggle, mul ) --bool play, int mul(tiplier)  (mul is optional)
	if self.playsound == 1 then
		if not mul then mul = 100 end
		if playtoggle then
			util.PrecacheSound( "weapons/crossbow/bolt_load1.wav" )
			self.Entity:EmitSound( "weapons/crossbow/bolt_load1.wav", mul, 100 )
		end
	end
end

function ENT:EmitShootEffects() --because all the young'ns need that visual feedback
	local cannonfx = EffectData()
	cannonfx:SetOrigin( self:GetPos() )
	util.Effect( "HelicopterMegaBomb", cannonfx, true, true )
	util.Effect( "RagdollImpact", cannonfx, true, true )
end

function ENT:Shoot() --this shoots the actual cannonball
	local cball = ents.Create( "sd_cannonball" ) --create it
	cball:SetPos( self:GetPos() ) --place it
	cball:Spawn() --spawn it
	cball:SetAngles( self:GetAngles() ) --twist it
	cball:GetPhysicsObject():SetMass( 250 ) --this will kill someone if it hits them
	cball:KickBall( self.distmul, self.spreadmul )
	util.SpriteTrail( cball, 1, Color(10,10,10,100), false, 5.58, 0, 0.25, 1/(5.38)*0.5, "trails/smoke.vmt" ) --looks nice
	cball:SetNetworkedBool( "fired", true ) --tell the ball that it's fired
	
	if self.shouldexplode == 1 then
		cball:SetNetworkedBool( "explode", true )
	else
		cball:SetNetworkedBool( "explode", false )
	end
	
	if self.shouldignite == 1 then
		cball:SetNetworkedBool( "ignite", true )
	else
		cball:SetNetworkedBool( "ignite", false )
	end
	
	if self.shoulddestroy == 1 then
		cball:SetNetworkedBool( "destroy", true )
	else
		cball:SetNetworkedBool( "destroy", false )
	end
end

function ENT:KickBack( mul )
	self.Entity:GetPhysicsObject():ApplyForceCenter( (self.Entity:GetForward() * mul) )
end